﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Yunzuan.Foundation.Common;
using Yunzuan.Foundation.Web_api;
using static Yunzuan.Foundation.Web_api.MyHttpRequest;

namespace Yunzuan.Common
{
    public class MyHttpClient
    {
         

        public static async Task<string> PostAsync(string AccessKey, string AccessSecret, string requestUrl, string requestJson = "", int timeoutTryCount = 2)
        {
            //var response = await _httpClient.PostAsync("/", new FormUrlEncodedContent(parameters));

            //return await response.Content.ReadAsStringAsync();
            HttpClient _httpClient = new HttpClient();

            try
            {
                if (timeoutTryCount > 0)
                {
                    timeoutTryCount--;
                    string guid = Guid.NewGuid().ToString();
                    ///排序
                    var sortStr = string.Empty;
                    sortStr = NestedDictSort2Str(JsonConvert.DeserializeObject<JObject>(requestJson));
                    //签名
                    SignByParams(AccessKey, AccessSecret, guid, sortStr, out int totalSeconds, out string signStr);


                    HttpContent httpContent = new StringContent(requestJson);
                    httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    httpContent.Headers.Add("UUID", guid);
                    httpContent.Headers.Add("Auth", signStr);
                    httpContent.Headers.Add("Time", totalSeconds.ToString());
                    return await (await _httpClient.PostAsync(requestUrl, httpContent)).Content.ReadAsStringAsync();
                }
                return "";
            }
            catch (Exception ee)
            {
                //log.Debug(JsonConvert.SerializeObject($"requestUrl:{requestUrl},requestJson:{requestJson},ee:{ee}"));//此处调用日志记录函数记录日志
                return await PostAsync(AccessKey, AccessSecret, requestUrl, requestJson, timeoutTryCount);
                throw;
            }
        }
        public static async Task<string> GetAsync(string AccessKey, string AccessSecret, string requestUrl, int timeoutTryCount = 2)
        {
            HttpClient _httpClient = new HttpClient();

            try
            {
                if (timeoutTryCount > 0)
                {
                    timeoutTryCount--;
                    string guid = Guid.NewGuid().ToString();
                    SignByParams(AccessKey, AccessSecret, guid, "", out int totalSeconds, out string signStr);  //这里的id不是参数，所以签名不加入任何参数

                    _httpClient.DefaultRequestHeaders.Add("Auth", signStr);
                    _httpClient.DefaultRequestHeaders.Add("UUID", guid);
                    _httpClient.DefaultRequestHeaders.Add("Time", totalSeconds.ToString());
                    return await _httpClient.GetStringAsync(requestUrl);

                }
                return null;
            }
            catch (Exception ee)
            {
                //add 日志
                return await GetAsync(AccessKey, AccessSecret, requestUrl, timeoutTryCount);
            }

        }
        /// <summary>
        /// 将排序的参数与AK加入签名
        /// </summary>
        /// <param name="guid"></param>
        /// <param name="sbStr"></param>
        /// <param name="totalSeconds"></param>
        /// <param name="signStr"></param>
        /// <param name="tag"></param>
        public static void SignByParams(string AccessKey, string AccessSecret, string guid, string sbStr, out int totalSeconds, out string signStr, string tag = "erp")
        {
            byte[] secretBytes = Encoding.UTF8.GetBytes(AccessSecret);//转utf8的byte,不直接参与签名,用来初始化HMACMD5算法

            TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1); //得到日期最小值到现在的总时间秒
            totalSeconds = (int)ts.TotalSeconds;
            //拼接成参数准备加密
            byte[] SignBytes = Encoding.UTF8.GetBytes(totalSeconds.ToString() + guid + sbStr.ToString());


            //6,按约定密钥初始化HMACMD5 
            HMACMD5 myhmacMD5 = new HMACMD5(secretBytes);
            //使用HMAC给拼装好的字符串签名
            byte[] b_Stream = myhmacMD5.ComputeHash(SignBytes);


            //7.将摘要得到的字节流结果使用十六进制小写
            string result = string.Empty;
            for (int i = 0; i < b_Stream.Length; i++)
            {
                result += b_Stream[i].ToString("x2");
            }

            //8.把十六进制摘要使用BASE64编码，
            string s_ResultByBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(result));

            //9拼装到head
            signStr = AccessKey + ":" + s_ResultByBase64;
        }
        /// <summary>
        ///将前端JSON字典格式化参数顺序按AabBcdCD的格式 --递归
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public static string NestedDictSort2Str(JObject param)
        {
            param = ObjShort2Obj(param); //排序
            var str = new StringBuilder();
            foreach (var item in param)
            {
                if (item.Value.Type.ToString() == "Object")
                    str.Append(item.Key + NestedDictSort2Str((JObject)item.Value));
                else if (item.Value.Type.ToString() == "Array")
                    str.Append(item.Key + Array2Str((JArray)item.Value));
                else if (item.Value.Type.ToString() == "Boolean" || string.IsNullOrEmpty(item.Value.ToString()))
                    str.Append(item.Key);
                else str.Append(item.Key + item.Value);
            }
            return str.ToString();
        }
        /// <summary>
        /// 数组排序
        /// </summary>
        /// <param name="array"></param>
        /// <returns></returns>
        public static string Array2Str(JArray array)
        {
            var str = new StringBuilder();
            List<JToken> ps = array.ToList(); //是数组
            for (int i = 0; i < ps.Count(); i++)
            {
                if (ps[i].Type.ToString() == "Object")
                    str.Append(NestedDictSort2Str((JObject)ps[i]));
                else if (ps[i].Type.ToString() == "Array")
                    str.Append(Array2Str((JArray)ps[i]));
                else if (ps[i].Type.ToString() != "Boolean" && !string.IsNullOrEmpty(ps[i].ToString()))
                    str.Append(ps[i]);
            }
            return str.ToString();
        }
        /// <summary>
        /// 对象排序
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static JObject ObjShort2Obj(JObject obj)
        {

            Dictionary<string, object> d = new Dictionary<string, object>();
            foreach (var item in obj)
                d.Add(item.Key, item.Value);  //填充到字典中

            d = d.OrderBy(t => t.Key, StringComparer.Ordinal).ToDictionary(o => o.Key, p => p.Value);  //排序区分大小写
            return JsonConvert.DeserializeObject<JObject>(JsonConvert.SerializeObject(d)); //封装成JObject
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tttagKey"></param>
        /// <param name="requestUrl"></param>
        /// <param name="requestJson"></param>
        /// <param name="timeoutTryCount"></param>
        /// <param name="httpFileCollection"></param>
        /// <param name="reqLib"></param>
        /// <returns></returns>
        public static async Task<string> ToDataCenter(string tttagKey, string requestUrl, string requestJson = "", int timeoutTryCount = 2, HttpFileCollection httpFileCollection = null, RequestLib reqLib = 0)
        {  
            MyHttpRequest.GetAKByKey(tttagKey, out string AccessKey, out string AccessSecret);
            try
            {
                HttpClient _httpClient = new HttpClient() ;
                _httpClient.Timeout = TimeSpan.FromMinutes(1);

                if (timeoutTryCount > 0)
                {  
                    timeoutTryCount--;
                    string guid = Guid.NewGuid().ToString();
                    ///排序
                    var sortStr = string.Empty;
                    sortStr = NestedDictSort2Str(JsonConvert.DeserializeObject<JObject>(requestJson));
                    //签名
                    SignByParams(AccessKey, AccessSecret, guid, sortStr, out int totalSeconds, out string signStr); 

                    if (httpFileCollection != null)  //上传文件
                    {
                        using (var content = new MultipartFormDataContent())
                        {

                            for (var i = 0; i < httpFileCollection.AllKeys.Count(); i++)
                            {
                                //content.Add(CreateFileContent(httpFileCollection[i].InputStream, httpFileCollection[i].FileName));
                                var fileContent = new StreamContent(httpFileCollection[i].InputStream);
                                fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { FileName = ToHexString(httpFileCollection[i].FileName), Name = "file_data" };

                                content.Add(fileContent);
                            }
                            content.Headers.Add("UUID", guid);
                            content.Headers.Add("Auth", signStr);
                            content.Headers.Add("Time", totalSeconds.ToString());

                            //先屏蔽，因为用的正式数据库 ********************正式上线开通 
                            return await (await _httpClient.PostAsync(requestUrl, content)).Content.ReadAsStringAsync();  
                        }
                    }
                    else
                    {
                        if (reqLib == RequestLib.POST)
                        {
                            HttpContent httpContent = new StringContent(requestJson);
                            httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                            httpContent.Headers.Add("UUID", guid);
                            httpContent.Headers.Add("Auth", signStr);
                            httpContent.Headers.Add("Time", totalSeconds.ToString());
                            return await (await _httpClient.PostAsync(requestUrl, httpContent)).Content.ReadAsStringAsync();
                        }
                        else if (reqLib == RequestLib.DELETE)
                        {
                            _httpClient.DefaultRequestHeaders.Add("Auth", signStr);
                            _httpClient.DefaultRequestHeaders.Add("UUID", guid);
                            _httpClient.DefaultRequestHeaders.Add("Time", totalSeconds.ToString());
                            return await (await _httpClient.DeleteAsync(requestUrl)).Content.ReadAsStringAsync();
                        }
                        else if (reqLib == RequestLib.PUT)
                        {
                            HttpContent httpContent = new StringContent(requestJson);
                            httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                            httpContent.Headers.Add("UUID", guid);
                            httpContent.Headers.Add("Auth", signStr);
                            httpContent.Headers.Add("Time", totalSeconds.ToString());
                            return await (await _httpClient.PutAsync(requestUrl, httpContent)).Content.ReadAsStringAsync();
                        }
                        if (reqLib == RequestLib.GET) //获取订单 GET提交
                        {
                            _httpClient.DefaultRequestHeaders.Add("Auth", signStr);
                            _httpClient.DefaultRequestHeaders.Add("UUID", guid);
                            _httpClient.DefaultRequestHeaders.Add("Time", totalSeconds.ToString());
                            return await _httpClient.GetStringAsync(requestUrl);
                        }
                    }
                }
                return null;
            }
            catch (Exception ee)
            {
                //add 日志
                return await GetAsync(AccessKey, AccessSecret, requestUrl, timeoutTryCount);
            }

        }


        public static async Task<string> GetRsultFromDataCenter(string tttagKey, string requestUrl, string requestJson = "", int timeoutTryCount = 2, HttpFileCollection httpFileCollection = null, RequestLib reqLib = 0)
        {
            
                return await ToDataCenter(tttagKey, requestUrl, requestJson, timeoutTryCount, httpFileCollection, reqLib); 
        }
        public static string GetRsultFromDataCenterNew(string tttagKey, string requestUrl, string requestJson = "", int timeoutTryCount = 2, HttpFileCollection httpFileCollection = null, RequestLib reqLib = 0)
        {
            return GetRsultFromDataCenter(tttagKey, requestUrl, requestJson, timeoutTryCount, httpFileCollection, reqLib).Result;
        }
    }
}
